import os, sys
from xml.dom import minidom
import CAConfig
from pyglet import image
from pyglet.gl import *
import Util

try:
    import simplejson
except:
    sys.path.append('lib/thirdparty')
    from thirdparty import simplejson

CACHE = {
    "tilesets": [],
    "chunks": []
}

# honestly this is a bad idea, things like this take a while to do and should
# be done on demand
def boot():
    ts_dir = os.path.join( CAConfig.basepath, 'resources', 'static_maps' )
    CACHE["tilesets"] = [TileSet( os.path.join(ts_dir,ts) )
        for ts in os.listdir( ts_dir )
        if ts.endswith('.tsx')]

def get_tileset(name):
    for ts in CACHE["tilesets"]:
        if name == ts.name:
            return ts
    return None

def pyglet_to_tiled( tileset ):
    """
    Flips the y around so that ImageGrids will map directly to
    the layout of a tiled map file.
    """
    # builds a 2d array in chunks of 8 and then flips them
    # this accomplishes the flipping of the y coord
    # the new 2d array is flattened and returned
    # [::-1] is a shortcut to reverse a list
    return Util.flatten([
        tileset.grid[i:i+tileset.columns]
        for i in range(0,len(tileset.grid),tileset.columns)
        ][::-1])

class StaticMapTileset:
    """
    Represents on 'tileset' instance in a Tiled tsx map file.

    first_gid is the first gid assigned to the image from tiled. This is used
    as an offset to find the right image.

    grid is the processed ImageGrid instance from pyglet.
    """
    def __init__(self, ts):
        self.first_gid = int(ts['firstgid'])
        self.grid = pyglet_to_tiled(
                get_tileset(ts['source'].rpartition('.tsx')[0]))

# This is a total mess
# Tiled reads top to bottom left to right
# pyglet reads bottom to top left to right
# tiled also starts counting at 1 instead of 0
# please make this hurt less :(
class StaticMap:
    def __init__(self,mapfile):
        # read in the map file
       
        f = pyglet.resource.file(mapfile)
        self.data = simplejson.load(f)
        f.close()
        _map = self.data['map']

        # load up all the necessary tilesets
        self.tilesets = [StaticMapTileset(ts) for ts in _map['tileset']]

        # figure out the basic map dimensions
        tile_width = int(_map['tilewidth'])
        tile_height = int(_map['tileheight'])
        map_w = int(_map['width'])
        map_h = int(_map['height'])

        # tiled starts counting at 1 instead of 0, so subtract that here
        tiles = [int(t['gid']) for t in self.data['map']['layer']['data']['tile']]
        self.background = image.Texture.create_for_size(
            GL_TEXTURE_2D,
            map_w * tile_width,
            map_h * tile_height,
            GL_RGB)

        for y in range( 0, map_h ):
            for x in range( 0, map_w ):
                # pyglet draws from the bottom left so we have to invert the y coord
                tile_gid = tiles[(map_h-1-y)*map_w + x]
                tile = self.get_tile(tile_gid)
                self.background.blit_into( tile, x * tile_width, y * tile_height, 0 )

    def get_tile(self,gid):
        """
        Returns the correct tile for the supplied gid.
        """
        good_ts = None
        for ts in self.tilesets:
            if gid >= ts.first_gid:
                good_ts = ts
        return good_ts.grid[gid - good_ts.first_gid].get_image_data()


class Map:
    """
    Map has n Chunks has n Tiles
    """
    def __init__(self):
        self.tileset = None
        self.name    = ""
    

class Chunk:
    """
    A rectangular arrangement of tiles
    """
    def __init__(self):
        self.layers = []


class Tile:
    """
    A single 32 by 32 area
    
    x: x coordinate for lower righthand pixel
    y: y coordinate for lower righthand pixel
    altitude: 'height' of the tile, used for movement restriction
    g_offset: tile location in a standard tileset
    chunk: parent chunk of this tile
    """
    def __init__(self):
        # required
        self.x        = 0
        self.y        = 0
        self.g_offset = 0
        self.chunk    = None
        # optional
        self.altitude = 0
        self.flags    = []
        
    def draw(self):
        pass

class TileSet:
    """
    Reads a Tiled .tmx tileset xml document.
    I hate DOM...
    """
    def __init__(self,f):
        doc = minidom.parse(f)
        src = doc.firstChild.childNodes[1].getAttribute('source')
        try:
            # basename of the file /path/to/basename.png
            sheet = pyglet.resource.image(src.split(os.path.sep)[-1])
        except:
            print pyglet.resource.path
            raise Exception, "Could not load source image (%s)" % src
        self.tile_width = int(doc.firstChild.getAttribute('tilewidth'))
        self.tile_height = int(doc.firstChild.getAttribute('tileheight'))
        self.key = doc.firstChild.childNodes[1].getAttribute('trans') or None
        self.name = doc.firstChild.getAttribute('name')
        self.columns = sheet.width // self.tile_width
        self.grid = image.ImageGrid(sheet, self.tile_width, self.columns)
